import axios from 'axios'

// 直接引入路由实例和vuex实例
// 因为组件是一个vue实例，所以它有$router和$store
import Vue from 'vue'
const vm = new Vue()

// 通用数据配置
const Axios = axios.create({
  timeout: 25000,
  baseURL: '/fuxingtong'
})

// axios有拦截器
// 实现通用数据注入 -- /user/login /user/validate/code /user/app/login 三个接口，其它都必须在请求头上添加token数据
// 定义不需要拦截接口
const other = ['/user/login', '/user/validate/code', '/user/app/login']
// 实现接口访问权限拦截 -- 后端可以在用户登录以后，返回一个数组，这个数组中返回的都是用户可以访问的接口['/user/update', '/user/info', '/user/delete/']
// 分为之前和之后
// 之前的拦截叫前端拦截，但是前端不可能做到100%的安全，所以后端也需要做拦截，我们可以约定403表示用户的token失效，非法用户
// 因此需要做请求之后的拦截

// {code: undefined, message: "Cannot read properties of undefined (reading 'cancelToken')"}
// 钩子函数一定要返回值(AxiosRequestConfig | Promise)
const requestHook = function (config) {
  // 因为它要求返回一个AxiosRequestConfig对象，那么可以在这里进行数据注入
  // 判断请求地址，是否需要注入token，如果不需要则不注入，如果需要，token还没有，那么就是非法用户，终止请求
  if (other.includes(config.url)) return config

  // let token = 'fldjsfjlkdsjflksjl'
  let token = vm.$myStore.getters['common/token']
  if (!token) return Promise.reject({
    code: 400,
    message: '没有token数据，不可以发出请求'
  })

  // 判断用户是否有接口访问权限['/user/update', '/user/info', '/user/delete/'].includes(config.url)

  config.headers.token = token
  return config
}

// use(onFulfilled?: (value: AxiosRequestConfig) => AxiosRequestConfig | Promise): number
// use方法接收一个onFulfilled参数，然后onFulfilled参数的数据类型为一个函数
// (value: AxiosRequestConfig) => AxiosRequestConfig | Promise 这个函数会有一个AxiosRequestConfig入参，要求返回AxiosRequestConfig对象或则Promise
Axios.interceptors.request.use(requestHook)

// 实现响应拦截
// AxiosInterceptorManager.use(onFulfilled?: (value: AxiosResponse<any, any>) => void | Promise)
Axios.interceptors.response.use(function (response) {
  let {
    data
  } = response
  // 判断data的code是否是403，message是否为："Request information authentication failed."
  if (data.code === 403 && data.message === "Request information authentication failed.") {
    alert('用户登录失效，请重新登录')
    vm.$myRouter.push('/login')
  } else {
    return response
  }
})

// 基于Promise
/**
 * 封装的axios异步请求方法
 * @param {{url: string, method: 'get' | 'post' | 'delete' | 'put', data: any, params: any}} req 请求对象
 * @return Promise
 */
export default req => {
  if (!req || !req.url) throw new TypeError('url地址必传')
  return new Promise(resolve => {
    Axios({
      url: req.url,
      // 默认为post
      method: req.method || 'get',
      params: req.params || {},
      data: req.data || {}
    }).then(({
      data
    }) => {
      resolve(data)
    }).catch(({
      code,
      message
    }) => {
      resolve({
        code,
        message
      })
    })
  })
}
